<template>
  <div @mouseenter="handleMouseEnter" @mouseleave="handleMouseLeave">
    <div v-if="Props.sankeyData != null">
      <div class="chart-wrapper">
        <div>
          <el-button type="info" size="small" link>
            <el-icon><Guide /></el-icon>
            <span>流量桑基图</span>
          </el-button>
          <el-divider direction="vertical" />
          <el-button
            :type="valueSelect == 'none' ? 'warning' : 'info'"
            size="small"
            :link="valueSelect != 'none'"
            @click="handleValueSelect('none')"
          >
            <el-icon><Hide /></el-icon>
            <span>隐藏</span>
          </el-button>
          <el-button
            :type="valueSelect == 'value' ? 'primary' : 'info'"
            size="small"
            :link="valueSelect != 'value'"
            @click="handleValueSelect('value')"
          >
            <el-icon><Promotion /></el-icon>
            <span>架次</span>
          </el-button>
          <el-button
            :type="valueSelect == 'load' ? 'success' : 'info'"
            size="small"
            :link="valueSelect != 'load'"
            @click="handleValueSelect('load')"
          >
            <el-icon><Odometer /></el-icon>
            <span>负荷</span>
          </el-button>
          <el-divider direction="vertical" />
          <el-button v-if="isHovering" type="warning" size="small" link>
            <el-icon><VideoPause /></el-icon>
            <!-- <span>已暂停刷新</span> -->
          </el-button>
          <el-button v-else type="info" size="small" link>
            <el-icon><VideoPlay /></el-icon>
            <!-- <span>自动刷新</span> -->
          </el-button>
        </div>
        <div>
          <el-button
            :type="isDataExpired ? 'danger' : 'info'"
            size="small"
            :link="!isDataExpired"
          >
            <el-icon v-if="isDataExpired"><WarningFilled /></el-icon>
            <el-icon v-else><SuccessFilled /></el-icon>
            <span>NTFM数据更新于</span>
            <span style="font-weight: bolder; padding: 0 4px">
              {{ dataFreshness }}
            </span>
            <span>分钟前</span>
            <span v-if="isDataExpired">（已过期）</span>
          </el-button>
        </div>
      </div>
      <el-collapse-transition>
        <v-chart
          v-if="valueSelect != 'none'"
          :option="chartOptions"
          :init-options="{ width: chartWidth, height: 400 }"
          ref="chart"
        />
        <!-- :init-options="{ width: chartWidth, height: 400 }" -->
        <!-- :style="{ width: chartWidth + 'px', height: '400px' }" -->
        <!-- autoresize -->
      </el-collapse-transition>
    </div>
    <div v-else><el-empty></el-empty></div>
  </div>
</template>

<script setup>
import { h, ref, computed, nextTick, watch, onMounted, onUnmounted } from "vue";
import dayjs from "dayjs";
import { ElMessage } from "element-plus";
import useCommonStore from "@/store/common.js";
import useFlowStore from "@/store/flow.js";

// import echarts
import * as echarts from "echarts/core";
import { SVGRenderer, CanvasRenderer } from "echarts/renderers";
import { SankeyChart } from "echarts/charts";
import { TooltipComponent } from "echarts/components";
import { LabelLayout } from "echarts/features";
import VChart, { THEME_KEY } from "vue-echarts";

echarts.use([
  // SVGRenderer,
  CanvasRenderer,
  SankeyChart,
  TooltipComponent,
  LabelLayout,
]);

const commonStore = useCommonStore();
const flowStore = useFlowStore();

const Props = defineProps({
  sankeyData: {
    type: Object,
    required: true,
  },
});

const dataFreshness = computed(() => parseInt(flowStore.freshness / 60));
const isDataExpired = computed(() => flowStore.freshness > 600);

const chart = ref();

const chartWidth = computed(() =>
  Math.max(
    commonStore.clientWidth -
      (commonStore.showSidebar ? commonStore.sidebarWidth : 0) -
      60,
    450
  )
);

const makeOptionsTimer = ref();
const makeOptionsInterval = 2 * 1000;
const mouseLeaveTimeout = 5 * 1000;

onMounted(() => {
  makeOptions();
  makeOptionsTimer.value = setInterval(
    () => makeOptions(),
    makeOptionsInterval
  );
  chart.value.resize();
  window.addEventListener("resize", function () {
    chart.value.resize();
  });
});

onUnmounted(() => {
  clearInterval(makeOptionsTimer.value);
  makeOptionsTimer.value = null;
});

watch(
  () => [commonStore.showSidebar],
  async () => {
    if (chart && chart.value) {
      await nextTick();
      chart.value.resize();
    }
  }
);

const valueSelect = ref("value");
// const typeSelect = ref("ARR");

const handleValueSelect = (selection) => {
  if (valueSelect.value != selection) {
    valueSelect.value = selection;
    refreshChart();
  }
};

const findNodeColor = (seat) => {
  let color = "#CCCCCC";
  if (commonStore.darkMode) {
    color = flowStore.seatColors[seat][0];
  } else {
    color = flowStore.seatColors[seat][1];
  }
  return color;
};

const findLinkColor = (type, airport) => {
  if (airport == "ZUUU") {
    if (type == "ARR") {
      return "#F83";
    } else if (type == "DEP") {
      return "#39F";
    }
  } else if (airport == "ZUTF") {
    if (type == "ARR") {
      return "#FD6";
    } else if (type == "DEP") {
      return "#3F6";
    }
  }
  return "#F06";
};

const findPointColor = (point) => {
  if (point.type == "airport") {
    if (point.name == "ZUUU") {
      return "#FF9999";
    } else if (point.name == "ZUTF") {
      return "#66DDFF";
    }
  } else {
    if (point.type2 == "ARR") {
      return "#FFFF99";
    } else if (point.type2 == "DEP") {
      return "#66FFAA";
    }
  }
  return commonStore.darkMode ? "#CCCCCC" : "#666666";
};

const nodeData = computed(() => {
  // seat node
  let data = Props.sankeyData.nodeData.map((cell, index) => {
    return {
      name: cell.name,
      value: valueSelect.value == "load" ? cell.value2 : cell.value,
      // depth: index + 1,
      itemStyle: {
        color: findNodeColor(cell.name),
      },
    };
  });
  // point node
  Object.keys(Props.sankeyData.shortPoints).forEach((key) => {
    let point = Props.sankeyData.shortPoints[key];
    data.push({
      name: point.name,
      value: point.value,
      // depth: point.type == "point" ? 0 : Props.sankeyData.nodeData.length + 1,
      itemStyle: {
        color: findPointColor(point),
      },
    });
  });
  return data;
});

const linkData = computed(() => {
  let data = new Array();
  Object.keys(Props.sankeyData.linkData).forEach((key) => {
    let cell = Props.sankeyData.linkData[key];
    if (cell.source && cell.target) {
      // cell.type == typeSelect.value &&
      let snum = parseInt(cell.source.replace(/[^0-9]/gi, ""));
      let tnum = parseInt(cell.target.replace(/[^0-9]/gi, ""));
      let source = cell.source;
      let target = cell.target;
      let toggled = false;
      if (snum > 0 && tnum > 0 && snum > tnum) {
        source = cell.target;
        target = cell.source;
        toggled = true;
      }
      data.push({
        source: source,
        target: target,
        realSource: cell.source,
        realTarget: cell.target,
        value: valueSelect.value == "load" ? cell.value2 : cell.value,
        type: cell.type,
        airport: cell.airport,
        toggled: toggled,
        lineStyle: {
          color: findLinkColor(cell.type, cell.airport),
        },
      });
    }
  });
  return data;
});

const lastHoverTime = ref(0);
const isHovering = ref(false);

const handleMouseEnter = () => {
  if (!isHovering.value) {
    // console.log("sankeyFrozed");
    // ElMessage("桑基图已暂停刷新");
  }
  isHovering.value = true;
  lastHoverTime.value = new Date().getTime();
};

const handleMouseLeave = () => {
  setTimeout(() => {
    if (
      isHovering.value &&
      new Date().getTime() - lastHoverTime.value > mouseLeaveTimeout
    ) {
      isHovering.value = false;
      // console.log("sankeyRestored");
      // ElMessage("桑基图已恢复刷新");
    }
  }, mouseLeaveTimeout);
};

const chartOptions = ref(null);
const makeOptions = (immediately = false) => {
  if (isHovering.value && chartOptions.value && !immediately) {
    return chartOptions.value;
  }
  if (
    chartOptions.value != null &&
    chartOptions.value.series &&
    chartOptions.value.series[0]
  ) {
    chartOptions.value.series[0].data = nodeData.value;
    chartOptions.value.series[0].links = linkData.value;
    return chartOptions.value;
  }
  let options = {
    tooltip: {
      trigger: "item",
      triggerOn: "mousemove",
    },
    series: [
      {
        type: "sankey",
        left: 50,
        right: 60,
        top: 20,
        bottom: 10,
        data: nodeData.value,
        links: linkData.value,
        emphasis: {
          focus: "adjacency",
        },
        lineStyle: {
          opacity: 0.35,
        },
        itemStyle: {
          borderWidth: 1,
          borderColor: "rgba(0, 0, 0, 0.25)",
          shadowColor: "rgba(0, 0, 0, 0.75)",
          shadowBlur: 10,
        },
        tooltip: {
          formatter: (params) => tooltipFormater(params),
        },
        label: {
          // position: "bottom",
          color: commonStore.darkMode ? "#fff" : "#000",
          textBorderColor: commonStore.darkMode ? "#000" : "#fff",
          textShadowColor: commonStore.darkMode ? "#000" : "#fff",
          textBorderWidth: 1,
          textShadowBlur: 4,
          fontWeight: "bolder",
          fontFamily: "'Consolas','sans-serif',monospace",
          fontSize: 14,
        },
        // nodeGap: 8,
        levels: [
          {
            depth: 0,
            label: {
              position: "left",
            },
          },
        ],
        animation: false,
        // animation: true,
        // animationDuration: function (idx) {
        //   // 越往后的数据时长越大
        //   return idx * 100;
        // },
        // animationDelay: function (idx) {
        //   // 越往后的数据延迟越大
        //   return idx * 100;
        // },
        // animationDurationUpdate: function (idx) {
        //   // 越往后的数据时长越大
        //   return idx * 100;
        // },
        // animationDelayUpdate: function (idx) {
        //   // 越往后的数据延迟越大
        //   return idx * 100;
        // },
      },
    ],
  };
  chartOptions.value = options;
  return options;
};

const tooltipFormater = (params) => {
  let data = params.data;
  let tooltip = "";
  if (data.name) {
    tooltip = `<div style="text-align:center;font-size:10px;">${data.name}通行${
      valueSelect.value == "value" ? "架次" : "负荷"
    }</div><div style="text-align:center;font-size:18px;font-weight:bolder;">${
      data.value
    }</div>`;
  } else {
    tooltip = `<div style="text-align:center;font-size:10px;">${
      data.type == "DEP" ? data.realTarget : data.realSource
    }向${data.type == "DEP" ? data.realSource : data.realTarget}移交<br />${
      data.airport
    }${data.type == "DEP" ? "离港" : data.type == "ARR" ? "进港" : "其他"}${
      valueSelect.value == "value" ? "架次" : "负荷"
    }</div><div style="text-align:center;font-size:18px;font-weight:bolder;">${
      data.value
    }</div>`;
  }
  return tooltip;
};

const refreshChart = () => {
  // lastHoverTime.value = 0;
  // isHovering.value = false;
  makeOptions(true);
};

defineExpose({ refreshChart });
</script>

<style scoped>
.chart-wrapper {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 3px 12px 0 12px;
}
</style>
